package demoMod.gdxform.ui;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Interpolation;
import demoMod.gdxform.core.AbstractAction;
import demoMod.gdxform.core.FormManager;
import demoMod.gdxform.helpers.FontHelper;
import demoMod.gdxform.interfaces.Border;
import demoMod.gdxform.interfaces.ResizeEventSubscriber;

public class GButton extends GLabel implements Border, ResizeEventSubscriber {
    private Color background = Color.DARK_GRAY.cpy();
    private Color border;
    private Color tmpColor = Color.DARK_GRAY.cpy();
    private float borderWidth;
    private Texture bgTexture;
    private Texture fgTexture;
    private Texture borderTexture;
    private boolean clicked = false;
    private boolean lastHovered = false;

    public GButton(float x, float y, float width, float height, BitmapFont font) {
        super(x, y, width, height, font);
    }

    public GButton(float x, float y, float width, float height) {
        super(x, y, width, height);
    }

    @Override
    public void render(SpriteBatch sb) {
        if (!this.visible()) return;
        sb.setColor(Color.WHITE);
        if (this.borderTexture != null) {
            sb.draw(this.borderTexture, getX(true) - borderWidth, getY(true) - borderWidth, getWidth() + borderWidth * 2, getHeight() + borderWidth * 2);
        }
        if (this.bgTexture != null) {
            sb.draw(this.bgTexture, getX(true), getY(true), getWidth(), getHeight());
        }
        if (this.fgTexture != null) {
            sb.draw(this.fgTexture, getX(true), getY(true), getWidth(), getHeight());
        }
        if (this.getFont() == null) return;
        FontHelper.renderFontCentered(sb, this.getFont(), this.getText(), getX(true) + getWidth() / 2.0F, getY(true) + getHeight() / 2.0F, this.getColor());
    }

    @Override
    public Color getBackground() {
        return background;
    }

    @Override
    public void setBackground(Color background) {
        if (!background.equals(this.background)) {
            this.background = background;
            refreshBackground();
        }
    }

    private void refreshBackground() {
        Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
        pixmap.setColor(this.background);
        pixmap.fill();
        if (this.bgTexture != null) {
            this.bgTexture.dispose();
        }
        this.bgTexture = new Texture(pixmap);
    }

    public void setFgTexture(Texture texture) {
        if (this.fgTexture != null) {
            this.fgTexture.dispose();
        }
        this.fgTexture = texture;
    }

    @Override
    public float getBorderWidth() {
        return borderWidth;
    }

    @Override
    public void setBorderWidth(float borderWidth) {
        this.borderWidth = borderWidth;
    }

    @Override
    public Color getBorder() {
        return this.border;
    }

    @Override
    public void setBorder(Color border) {
        if (this.borderWidth > 0) {
            this.border = border;
            refreshBorder();
        }
    }

    private void refreshBorder() {
        if (this.borderWidth == 0 || this.border == null) return;
        Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
        pixmap.setColor(this.border);
        pixmap.fill();
        if (this.borderTexture != null) {
            this.borderTexture.dispose();
        }
        this.borderTexture = new Texture(pixmap);
    }

    @Override
    public boolean clickDown(int screenX, int screenY, int button) {
        if (!this.visible() || !this.enabled()) return false;
        clicked = screenX >= getX(true) && screenX <= getX(true) + getWidth() &&
                Gdx.graphics.getHeight() - screenY >= getY(true) && Gdx.graphics.getHeight() - screenY <= getY(true) + getHeight();
        if (clicked && enabled()) {
            Color neg = Color.WHITE.cpy().sub(this.background);
            setBackground(neg);
            neg = Color.WHITE.cpy().sub(this.getColor());
            setColor(neg);
            FormManager.getInstance().getEventHooks().setCurrentFocusedElement(this);
        }
        return clicked;
    }

    @Override
    public boolean clickUp(int screenX, int screenY, int button) {
        if (!this.visible() || !this.enabled()) return false;
        if (clicked && enabled()) {
            Color neg = Color.WHITE.cpy().sub(this.background);
            setBackground(neg);
            neg = Color.WHITE.cpy().sub(this.getColor());
            setColor(neg);
            clicked = false;
            if (screenX >= getX(true) && screenX <= getX(true) + getWidth() &&
                    Gdx.graphics.getHeight() - screenY >= getY(true) && Gdx.graphics.getHeight() - screenY <= getY(true) + getHeight()) {
                onClick();
            }
            return true;
        }
        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        boolean mouseMoved = screenX >= getX(true) && screenX <= getX(true) + getWidth() &&
                Gdx.graphics.getHeight() - screenY >= getY(true) && Gdx.graphics.getHeight() - screenY <= getY(true) + getHeight();
        if (mouseMoved && !lastHovered) {
            Color target = Color.DARK_GRAY.cpy();
            Color transition = new Color();
            Color start = getBackground().cpy();
            tmpColor = getBackground().cpy();
            actionManager.clearSequence();
            actionManager.addToSequenceBot(new AbstractAction.Builder().setDuration(0.5F).setActionBody(duration -> {
                transition.r = Interpolation.linear.apply(start.r, target.r, 1.0F - (duration / 0.5F));
                transition.g = Interpolation.linear.apply(start.g, target.g, 1.0F - (duration / 0.5F));
                transition.b = Interpolation.linear.apply(start.b, target.b, 1.0F - (duration / 0.5F));
                transition.a = Interpolation.linear.apply(start.a, target.a, 1.0F - (duration / 0.5F));
                setBackground(transition);
                return duration < 0;
            }).build());
        } else if (!mouseMoved && lastHovered) {
            Color target = tmpColor.cpy();
            Color transition = new Color();
            Color start = getBackground().cpy();
            tmpColor = Color.DARK_GRAY.cpy();
            actionManager.clearSequence();
            actionManager.addToSequenceBot(new AbstractAction.Builder().setDuration(0.5F).setActionBody(duration -> {
                transition.r = Interpolation.linear.apply(start.r, target.r, 1.0F - (duration / 0.5F));
                transition.g = Interpolation.linear.apply(start.g, target.g, 1.0F - (duration / 0.5F));
                transition.b = Interpolation.linear.apply(start.b, target.b, 1.0F - (duration / 0.5F));
                transition.a = Interpolation.linear.apply(start.a, target.a, 1.0F - (duration / 0.5F));
                setBackground(transition);
                return duration < 0;
            }).build());
        }
        lastHovered = mouseMoved;
        return mouseMoved;
    }

    public void onClick() {

    }

    @Override
    public void dispose() {
        super.dispose();
        if (this.bgTexture != null) {
            this.bgTexture.dispose();
        }
        if (this.borderTexture != null) {
            this.borderTexture.dispose();
        }
        if (this.fgTexture != null) {
            this.fgTexture.dispose();
        }
    }

    @Override
    public void resize(float deltaX, float deltaY, boolean fromParent) {

    }
}
